import { Injectable } from '@nestjs/common'
import { AcrossService } from 'src/across/across.service'
import { BetService } from 'src/bet/bet.service'
import { CalculateAcrossService } from 'src/calculate-across/calculate-across.service'
import { CalculateTowerService } from 'src/calculate-tower/calculate-tower.service'
import { OtherService } from 'src/other/other.service'
import { PrismaService } from 'src/prisma/prisma.service'
import {
  calcAngle,
  calcF,
  calcFB,
  calcHi,
  calcTAFromTB,
  calcTBFromFB,
  calcTBFromTA,
} from 'src/section/utils/ljImageMath'
import { TowerService } from 'src/tower/tower.service'
import { WireService } from 'src/wire/wire.service'
import { CreateOrderDto } from './dto/create-order.dto'
import { UpdateOrderDto } from './dto/update-order.dto'
import { bet, tower } from '@prisma/client'
import { json } from 'stream/consumers'
import { SunOrderCalculate } from './calculate/SunCalculate'

@Injectable()
export class OrderService {
  constructor(
    private prisma: PrismaService,
    private towers: TowerService,
    private bets: BetService,
    private across: AcrossService,
    private other: OtherService,
    private wire: WireService,
    private calcTower: CalculateTowerService,
    private calcAcross: CalculateAcrossService,
  ) {}

  // 创建方向
  async create(createOrderDto: CreateOrderDto) {
    return await this.prisma.order.create({
      data: createOrderDto,
    })
  }

  async findAll(args: Record<string, any>) {
    const orders = await this.prisma.order.findMany()
    if (orders.length === 0) {
      await this.adddefaultOrder(args)
    }
    return await this.prisma.order.findMany()
  }

  /**
   * 添加默认的牵引方向
   */
  async adddefaultOrder(args: Record<string, any>) {
    const { sectionId } = args
    const towers = await this.towers.findAll({ sectionId })
    const others = await this.other.findAll({ sectionId })
    const wires = await this.wire.findAll({ sectionId })

    const orderName = '牵引导线'
    const moZuNum = others.find((o) => o.otherName === '摩阻系数').otherNum
    const wireNum = others.find((o) => o.otherName === '导线展放根数').otherNum
    const daoxianWeight = wires.find((w) => w.wireName === '导线').id
    const smallWireWeight = wires.find((w) => w.wireName === '小引绳').id
    const bigWireWeight = wires.find((w) => w.wireName === '大引绳').id

    let isStraight = false
    let zhangLiTowerId = 0
    let qianYinTowerId = 0
    if (towers[0].tName === '张力场') {
      isStraight = true
      zhangLiTowerId = towers[1].id
      qianYinTowerId = towers[towers.length - 2].id
    } else {
      isStraight = false
      zhangLiTowerId = towers[towers.length - 2].id
      qianYinTowerId = towers[1].id
    }
    // 添加牵引导线
    await this.create({
      orderName,
      isStraight,
      sectionId: +sectionId,
      moZuNum,
      wireNum,
      daoYinWireId: daoxianWeight,
      qianYinWireId: bigWireWeight,
      qianYinTowerId,
      zhangLiTowerId,
    })
    // 添加牵引引绳
    await this.create({
      orderName: '牵引引绳',
      isStraight: !isStraight,
      sectionId: +sectionId,
      moZuNum,
      wireNum: 1,
      daoYinWireId: bigWireWeight,
      qianYinWireId: smallWireWeight,
      qianYinTowerId: zhangLiTowerId,
      zhangLiTowerId: qianYinTowerId,
    })
  }

  async findOne(id: number) {
    return await this.prisma.order.findUnique({
      where: { id },
    })
  }

  async update(id: number, updateOrderDto: UpdateOrderDto) {
    return this.prisma.order.update({
      where: { id },
      data: updateOrderDto,
    })
  }

  async remove(id: number) {
    return await this.prisma.order.delete({
      where: { id },
    })
  }

  // 此区段方向的所有计算开启按钮
  async calculate(id: number) {
    // // 获取id的calculate_across中是否有数据
    // const lst_calc_tower = await this.calcTower.findAll({ orderId: id })
    // // 如果有，则不再计算，如果没有，则计算
    // if (lst_calc_tower.length !== 0) return '已计算过'

    // // 获取order所在的sectionId
    // const order = await this.findOne(id)
    // const sectionId = order.sectionId
    // const w = (await this.wire.findOne(order.daoYinWireId)).wireWeight
    // const w0 = (await this.wire.findOne(order.qianYinWireId)).wireWeight
    // const m = order.wireNum
    // const e = order.moZuNum

    // // 获取sectionId的集合列表
    // const lst_tower = await this.towers.findAll({ sectionId })
    // const lst_bet = await this.bets.findAll({ sectionId })
    // const lst_across = await this.across.findAll({ sectionId })

    // // 计算控制点的受力
    // for (const across of lst_across) {
    //   const n = across.acrossX
    //   const l = across.bet.btSpan

    //   const [t1, t2] = across.btName.split('--')
    //   const tower1 = lst_tower.find((t) => t.tName === t1)
    //   const tower2 = lst_tower.find((t) => t.tName === t2)
    //   const h = tower2.altitude - tower1.altitude

    //   const N = tower1.altitude
    //   const y = across.acrossY + across.controlHeight

    //   const angle = calcAngle(h, l)
    //   const Hi = calcHi(w, n, l, N, y, angle)
    //   const f = calcF(l, w, Hi, angle) // 最大弧垂
    //   const FB = calcFB(f, h)

    //   /**
    //    * 计算出口张力Ti
    //    */
    //   const index = lst_bet.findIndex((bet) => bet.btName === across.btName)
    //   // 计算第index档内TB
    //   let TB = calcTBFromFB(Hi, w, FB, angle)
    //   // 计算第index档内TA
    //   let TA = calcTAFromTB(TB, w, h, angle)
    //   // 计算第index-1档内TB
    //   for (let i = index - 1; i >= 0; i--) {
    //     TB = TA / e

    //     const [tname1, tname2] = lst_bet[i].btName.split('--')
    //     const tower1 = lst_tower.find((t) => t.tName == tname1)
    //     const tower2 = lst_tower.find((t) => t.tName == tname2)
    //     const high = tower2.altitude - tower1.altitude
    //     const ang = calcAngle(high, lst_bet[i].btSpan)

    //     TA = calcTAFromTB(TB, w, high, ang)
    //   }
    //   // 得到出口张力
    //   const TT = TA

    //   await this.calcAcross.create({
    //     acrossId: across.id,
    //     orderId: id,
    //     FB,
    //     Hi,
    //     rank: 0,
    //     TT,
    //   })
    // }

    // // 将数据根据TT排序
    // await this.calcAcross.setRank({ orderId: id })
    // // 计算张力整定值
    // const Ti = await this.calcTi(id)
    // 计算铁塔受力
    // await this.calcTowerPower(id, lst_tower, lst_bet, Ti, w, w0, e, m)
    new SunOrderCalculate(this.towers, this.bets, this.across, this.wire, this, this.calcTower, this.calcAcross).calc(
      id,
    )
    return '计算完成'
  }

  // 计算张力整定值
  async calcTi(id: number) {
    const lst_calc_across = await this.calcAcross.findAll({ orderId: id })
    // 找到TT最大的计算数据
    const calc_across_max = lst_calc_across.find((ca) => ca.rank === 1)
    // 得到最大的出口张力，即张力整定值
    const Ti = calc_across_max.TT

    return Ti
  }

  // 计算铁塔受力
  async calcTowerPower(
    id: number,
    lst_tower: tower[],
    lst_bet: bet[],
    Ti: number,
    w: number,
    w0: number,
    e: number,
    m: number,
  ) {
    // 记录走板所到的塔位编号 i
    for (let i = 0; i < lst_tower.length; i++) {
      const lst = this.calcSigleTowerPower(i, lst_tower, lst_bet, Ti, w, w0, e, m)
      await this.calcTower.create({
        orderId: id,
        towerId: lst_tower[i].id,
        TAs: JSON.stringify(lst),
      })
    }
  }

  // 计算单个区段的铁塔受力
  calcSigleTowerPower(
    i: number,
    lst_tower: tower[],
    lst_bet: bet[],
    Ti: number,
    w: number,
    w0: number,
    e: number,
    m: number,
  ) {
    const lst_ta = []
    // 张力机轴向张力
    let TA = Ti
    let TB = 0
    lst_ta.push(TA.toFixed(2))

    for (const bet of lst_bet) {
      const [tn1, tn2] = bet.btName.split('--')
      const t1 = lst_tower.find((t) => t.tName === tn1)
      const t2 = lst_tower.find((t) => t.tName === tn2)
      const h = t2.altitude - t1.altitude
      const angle = calcAngle(h, bet.btSpan)

      // n 记录所在的bet的编号，牵引侧 n# 塔的轴向张力
      // 应注意 n 是以 0 开始的，而第 0 基杆塔应该是张力场，那么就需要 +1
      const n = lst_bet.findIndex((b) => b === bet) + 1

      if (n <= i) {
        // 如果 n < i,表示计算塔位 n# 在 i# 张力侧，所在区段的绳索都是牵引绳或者导线
        // 如果 n = i，表示在 n# 张力侧绳索是牵引绳或者导线，牵引侧绳索是导引绳
        TB = calcTBFromTA(TA, w, m, h, angle)
      } else {
        TB = calcTBFromTA(TA, w0, 1, h, angle)
      }

      // 第n+1基杆塔TA
      TA = TB * e

      lst_ta.push(TA.toFixed(2))
    }

    return lst_ta
  }

  async removeAll(sectionId: number) {
    return await this.prisma.order.deleteMany({ where: { sectionId } })
  }
}
